package com.ytktt.study.week8.task6.hmily.tcc.stock.service;

import com.ytktt.study.week8.task6.hmily.tcc.stock.api.ItemStockService;
import com.ytktt.study.week8.task6.hmily.tcc.stock.dto.ItemStockDTO;
import com.ytktt.study.week8.task6.hmily.tcc.stock.entity.ItemStockEntity;
import com.ytktt.study.week8.task6.hmily.tcc.stock.mapper.ItemStockMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hmily.annotation.HmilyTCC;
import org.dromara.hmily.common.exception.HmilyRuntimeException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * TODO
 *
 * @author ytk
 */
@Slf4j
@Service("itemStockService")
@RequiredArgsConstructor
public class ItemStockServiceImpl implements ItemStockService {

    private static final AtomicInteger CONFIRM_COUNT = new AtomicInteger(0);
    private final ItemStockMapper itemStockMapper;
    
    @Override
    @HmilyTCC(confirmMethod = "confirmMethod", cancelMethod = "cancelMethod")
    public Boolean decrease(ItemStockDTO itemStockDTO) {
        return itemStockMapper.updateDecrease(this.convertDtoToEntity(itemStockDTO)) > 0;
    }

    @Override
    public Boolean testDecrease(ItemStockDTO itemStockDTO) {
        this.itemStockMapper.updateTestDecrease(this.convertDtoToEntity(itemStockDTO));
        return true;
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmMethod", cancelMethod = "cancelMethod")
    public String mockWithTryException(ItemStockDTO itemStockDTO) {
        throw new IllegalArgumentException("库存扣减异常");
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmMethod", cancelMethod = "cancelMethod")
    public Boolean mockWithTryTimeout(ItemStockDTO itemStockDTO) {
        try {
            //模拟延迟 当前线程暂停10秒
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        final int decrease = this.itemStockMapper.updateDecrease(this.convertDtoToEntity(itemStockDTO));
        if (decrease != 1) {
            throw new IllegalArgumentException("库存不足");
        }
        return true;
    }

    @Override
    @HmilyTCC(confirmMethod = "confirmMethod", cancelMethod = "cancelMethod")
    public Boolean mockWithConfirmTimeout(ItemStockDTO itemStockDTO) {
        log.info("==========调用扣减库存try mockWithConfirmTimeout===========");
        final int decrease = this.itemStockMapper.updateDecrease(this.convertDtoToEntity(itemStockDTO));
        if (decrease != 1) {
            throw new HmilyRuntimeException("库存不足");
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean confirmMethodTimeout(ItemStockDTO itemStockDTO) {
        try {
            //模拟延迟 当前线程暂停11秒
            Thread.sleep(11000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("==========调用扣减库存确认方法===========");
        this.itemStockMapper.updateConfirm(this.convertDtoToEntity(itemStockDTO));
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean confirmMethodException(ItemStockDTO itemStockDTO) {
        log.info("==========调用扣减库存确认方法===========");
        final int decrease = this.itemStockMapper.updateDecrease(this.convertDtoToEntity(itemStockDTO));
        if (decrease != 1) {
            throw new HmilyRuntimeException("库存不足");
        }
        return true;
    }

    public Boolean confirmMethod(ItemStockDTO itemStockDTO) {
        log.info("==========调用扣减库存confirm方法===========");
        this.itemStockMapper.updateConfirm(this.convertDtoToEntity(itemStockDTO));
        final int i = CONFIRM_COUNT.incrementAndGet();
        log.info("调用了inventory confirm " + i + " 次");
        return true;
    }

    public Boolean cancelMethod(ItemStockDTO itemStockDTO) {
        log.info("==========调用扣减库存取消方法===========");
        this.itemStockMapper.updateCancel(this.convertDtoToEntity(itemStockDTO));
        return true;
    }

    private ItemStockEntity convertDtoToEntity(ItemStockDTO itemStockDTO) {
        ItemStockEntity entity = new ItemStockEntity();
        entity.setItemId(itemStockDTO.getItemId());
        entity.setLockStock(itemStockDTO.getAmount());
        return entity;
    }
}
